package com.lanhao.aot.carrierintegration.dgou;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import com.beust.jcommander.internal.Maps;
import com.google.common.collect.Lists;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.UUID;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;

public class DaiGouUtil {
	private static final Logger LOG = LoggerFactory.getLogger(DaiGouUtil.class);

	private static final String MERCHANT_ID = "C225R1";
	private static final String GRANT_TYPE = "client_credentials";
	private static final String CLIENT_ID = "4SAPm1G5CEu3ics3AxjuazgVo6eFbnl5alAr9TgsjmCq5mwI";
	private static final String CLIENT_SECRET = "5IZ4d3fux5sQXHcxVBBsQDEHutDvspMlkV9eKhRN2X1jhPxKQ66zfg02OtC8jPeT";
	private static final String BASE_URL = "https://wwwcie.ups.com";
	private static final String TOKEN_URL = BASE_URL + "/security/v1/oauth/token";
//	private static final String AUTHORIZE_URL = BASE_URL + "/security/v1/oauth/authorize";
	private static final String SHIPPMENT_URL = BASE_URL + "/api/shipments/v1/ship?additionaladdressvalidation=1";

	private static final String BASIC_AUTH = "Basic ";
	private static final String BEARER_AUTH = "Bearer ";

	// @我还要怎样更好的世界  刚收到美国那边的回复，这种情况还是要按照退货处理，具体到报文上就是要添加ImportControl这一部分，shipper为国内的信息，ship to也是国内的信息，ship from为国外的信息，然后付款用国内的账号。我刚才具体测了一下，美国到上海，具体请参考报文和响应
	public static void main(String[] args) {
		String token = genAccessToken();
		createShipment(token);
	}

	public static String genAccessToken() {
		Map<String, String> header = Maps.newHashMap();
		header.put("x-merchant-id", MERCHANT_ID);
		final String encodedClientIdAndSecret = Base64
				.encode((CLIENT_ID + ':' + CLIENT_SECRET).getBytes(StandardCharsets.UTF_8));
		header.put(HttpHeaders.AUTHORIZATION, BASIC_AUTH + encodedClientIdAndSecret);

		Map<String, Object> m = Maps.newHashMap();
		m.put("grant_type", GRANT_TYPE);

		HttpResponse response = HttpRequest.post(TOKEN_URL).addHeaders(header).form(m).execute();
		String respBody = response.body();
		LOG.info("获取token返回信息respBody={}", respBody);
		JSONObject respObject = JSON.parseObject(respBody);
		if (response.getStatus() == HttpStatus.HTTP_OK) {
			// 获取token返回信息respBody={"token_type":"Bearer","issued_at":"1701503945736","client_id":"4SAPm1G5CEu3ics3AxjuazgVo6eFbnl5alAr9TgsjmCq5mwI","access_token":"eyJraWQiOiI2NGM0YjYyMC0yZmFhLTQzNTYtYjA0MS1mM2EwZjM2Y2MxZmEiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJzdWIiOiJ4bGlhbmdzaHVhbmdAdXBzLmNvbSIsImNsaWVudGlkIjoiNFNBUG0xRzVDRXUzaWNzM0F4anVhemdWbzZlRmJubDVhbEFyOVRnc2ptQ3E1bXdJIiwibWVyX2lkIjoiQzIyNVIxIiwiaXNzIjoiaHR0cHM6Ly9hcGlzLnVwcy5jb20iLCJ1dWlkIjoiMkQ5Nzc2MTUtNkYwMy0xRTQ1LUJFREUtM0YwQjc4RkU3RTE3Iiwic2lkIjoiNjRjNGI2MjAtMmZhYS00MzU2LWIwNDEtZjNhMGYzNmNjMWZhIiwiYXVkIjoiRS1TSURFIiwiYXQiOiJHQXRHUGVMVm5SR3FtWkJGenFBTW5mTmpudUZWIiwibmJmIjoxNzAxNTAzOTQ1LCJEaXNwbGF5TmFtZSI6IkUtU0lERSIsImV4cCI6MTcwMTUxODM0NSwiaWF0IjoxNzAxNTAzOTQ1LCJqdGkiOiI3MDVjZTRlNy04YjA1LTQ0NjAtYWZhMS1hZTY1YmUyOTI4NjgifQ.GGqEQ9Z9tCbpFu_OFseELUZRknKZaUFjSiosLH7x8HMt0nplIu-7xGRL9C9NE0dI8y-NyI70LiILRKH6_wxzf-DbI-KyltlOpI2E_ez_XCfjeJD2skpwzczsgDPqluVM7B0Ysv5jmp4pez26c8xKyms5N8O6BFLQnqpR3WQNPiAD_iekkwI_C0F9pvNFRKbQkPWaBa8of8mdHD9qIqs79BdvkHNwNJqdWJ8am99T7fYM6vuYJ_kmfqUKRuKOTd_wXfvyUcUmJ-nsJP4phgmBZyGLjEpOTJyTBQdbFA76dwwkDtx9K1kVQLojLVqMUpBv0Wic2zclz0Hz9RY_IG0A3t-iBLvY1zz0aVygSnE91KIvpbsuq7kA0OXln7r52FPGq0c6En-lA9abUd1LI7bEOIW8T1PtWkiwQDBzR-O2Deq5mAM-2inatlCqvRPGuI8xC3XYzyq6on-PsLTis_OIEXUtFE46sKl7-PSSUV1RXBRwCCM4RLsqhooK6X7miLtMfliWF6cu8cojbTmCO2Qy_FGn29hTmThOs_Ay228XCSZMitL0wrbukzsexk9Dr1PVZgBAXwb_LEyh8r9VOdDQBxnyuAJHxVd2ZxWQKQH5pFavHGRA9w_wViJMqrs-lESB7etYGjX0Zz4tjK-VDWCH1fI_lcWmjOz0B7zOr0dpT0A","expires_in":"14399","status":"approved"}
			String accessToken = respObject.getString("access_token");
			Integer expiresIn = respObject.getInteger("expires_in");
			LOG.info("获取token返回成功，access_token={}，expires_in={}", accessToken, expiresIn);
			return accessToken;
		} else {
			JSONObject responseObject = respObject.getJSONObject("response");
			JSONArray errorArray = responseObject.getJSONArray("errors");
			JSONObject errorObject = errorArray.getJSONObject(0);
			String code = errorObject.getString("code");
			String message = errorObject.getString("message");
		}
		return "";
	}

	public static String createShipment(String accessToken) {
		Map<String, String> header = Maps.newHashMap();
		header.put("transId", UUID.fastUUID().toString(true));
		header.put("transactionSrc", "Test");
		header.put(HttpHeaders.CONTENT_TYPE, ContentType.JSON.name());
		header.put(HttpHeaders.AUTHORIZATION, BEARER_AUTH + accessToken);

		JSONObject payload = new JSONObject();
		JSONObject shipmentRequest = new JSONObject();
		JSONObject request = new JSONObject();
		request.put("SubVersion", "1801");
		request.put("RequestOption", "nonvalidate");
		JSONObject transactionReference = new JSONObject();
		transactionReference.put("CustomerContext", "");
		request.put("TransactionReference", transactionReference);
		shipmentRequest.put("Request", request);
		
		JSONObject shipment = new JSONObject();
		
		JSONObject shipmentServiceOptions = new JSONObject();
		shipmentServiceOptions.put("ImportControlIndicator", "");
		JSONObject labelMethod = new JSONObject();
		/**
		 * Valid LabelMethod types are: 
		 * 01 = ImportControl Print and Mail 
		 * 02 = ImportControl One-Attempt 
		 * 03 = ImportControl Three-Attempt 
		 * 04 = ImportControl Electronic Label 
		 * 05 = ImportControl Print Label
		 */
		labelMethod.put("Code", "04");
		shipmentServiceOptions.put("LabelMethod", labelMethod);
		
		JSONObject labelDelivery = new JSONObject();
		JSONObject mail = new JSONObject();
		mail.put("EMailAddress", "lanhaoooo@163.com");
		labelDelivery.put("EMail", mail);
		shipmentServiceOptions.put("LabelDelivery", labelDelivery);
		
		shipment.put("ShipmentServiceOptions", shipmentServiceOptions);
		
		shipment.put("Description", "Ship WS test");
		
		// shipper一般填写发件公司信息
		JSONObject shipper = new JSONObject();
		shipper.put("Name", "AliBaba");  // Shippers company name. 必填
		shipper.put("AttentionName", "-");
		shipper.put("TaxIdentificationNumber", "");
		
		JSONObject shipperPhone = new JSONObject();
		shipperPhone.put("Number", "18130064531");
		shipperPhone.put("Extension", "");
		shipper.put("Phone", shipperPhone);
		
		shipper.put("ShipperNumber", MERCHANT_ID); // TODO 确认下传什么
		shipper.put("FaxNumber", "");
		
		JSONObject shipperAddress = new JSONObject();
		shipperAddress.put("City", "Hefei"); // 必填
		shipperAddress.put("StateProvinceCode", "AnHui");
		shipperAddress.put("PostalCode", "230000");
		shipperAddress.put("CountryCode", "CN");// 必填
		List<String> shipperAddressLine = Lists.newArrayList("Huangshan Road 23");// 必填
		shipperAddress.put("AddressLine", shipperAddressLine);
		shipper.put("Address", shipperAddress);
		
		shipment.put("Shipper", shipper);
		
		// 收件地址信息
		JSONObject shipTo = new JSONObject();
		shipTo.put("Name", "KuKun"); // 必填
		shipTo.put("AttentionName", "-");
		
		JSONObject shipToPhone = new JSONObject();
		shipToPhone.put("Number", "18130064531");
		shipTo.put("Phone", shipToPhone);
		
		JSONObject shipToAddress = new JSONObject();
		shipToAddress.put("City", "Hefei"); // 必填
		shipToAddress.put("StateProvinceCode", "AnHui");
		shipToAddress.put("PostalCode", "230000");
		shipToAddress.put("CountryCode", "CN"); // 必填
		
		List<String> shipToAddressLine = Lists.newArrayList("Huangshan Road 25"); // 必填
		shipToAddress.put("AddressLine", shipToAddressLine);
		
		shipTo.put("Address", shipToAddress);
		shipTo.put("Residential", "");
		
		shipment.put("ShipTo", shipTo);
				
		/**
		 * Ship From Container. Required for return shipment. 
		 * Required if pickup location is different from the shipper's address.
		 * 
		 * 选国外的地址实际的发货地址信息
		 */
		JSONObject shipFrom = new JSONObject();
		shipFrom.put("Name", "USTestShipper");
		shipFrom.put("AttentionName", "-");
		shipFrom.put("FaxNumber", "");
		
		JSONObject shipFromPhone = new JSONObject();
		shipFromPhone.put("Number", "9225377171");
		shipFrom.put("Phone", shipFromPhone);
		
		JSONObject shipFromAddress = new JSONObject();
		shipFromAddress.put("City", "timonium");
		shipFromAddress.put("StateProvinceCode", "MD");
		shipFromAddress.put("PostalCode", "21030");
		shipFromAddress.put("CountryCode", "US");
		
		List<String> shipFromAddressLine = Lists.newArrayList("Huangshan Road 24");
		shipFromAddress.put("AddressLine", shipFromAddressLine);
		
		shipFrom.put("Address", shipFromAddress);
		
		shipment.put("ShipFrom", shipFrom);
		
		JSONObject paymentInformation = new JSONObject();
		JSONObject shipmentCharge = new JSONObject();
		shipmentCharge.put("Type", "01"); // 确认传什么
		
//		JSONObject billReceiver = new JSONObject();
//		billReceiver.put("AccountNumber", MERCHANT_ID);
//		shipmentCharge.put("BillReceiver", billReceiver);
		 
		JSONObject billShipper = new JSONObject();
		billShipper.put("AccountNumber", MERCHANT_ID);
		shipmentCharge.put("BillShipper", billShipper);
		
		paymentInformation.put("ShipmentCharge", shipmentCharge);
		shipment.put("PaymentInformation", paymentInformation);
		
		JSONObject service = new JSONObject();
		/**
		 	Valid values: 
		 	01 = Next Day Air 
		 	02 = 2nd Day Air 
		 	03 = Ground 
		 	07 = Express 
		 	08 = Expedited 
		 	11 = UPS Standard 
		 	12 = 3 Day Select 
		 	13 = Next Day Air Saver 
		 	14 = UPS Next Day Air Early 
		 	17 = UPS Worldwide Economy DDU 
		 	54 = Express Plus 
		 	59 = 2nd Day Air A.M. 
		 	65 = UPS Saver 
		 	M2 = First Class Mail 
		 	M3 = Priority Mail 
		 	M4 = Expedited MaiI Innovations 
		 	M5 = Priority Mail Innovations 
		 	M6 = Economy Mail Innovations 
		 	M7 = MaiI Innovations (MI) Returns 
		 	70 = UPS Access Point Economy 
		 	71 = UPS Worldwide Express Freight Midday 
		 	72 = UPS Worldwide Economy DDP 
		 	74 = UPS Express 12:00 
		 	75 = UPS Heavy Goods 
		 	82 = UPS Today Standard 
		 	83 = UPS Today Dedicated Courier 
		 	84 = UPS Today Intercity 
		 	85 = UPS Today Express 
		 	86 = UPS Today Express Saver 
		 	96 = UPS Worldwide Express Freight.
			Note: Only service code 03 is used for Ground Freight Pricing shipments.
			The following Services are not available to return shipment: 13, 59, 82, 83, 84, 85, 86
		 */
		service.put("Code", "65");
		service.put("Description", "Express");
		shipment.put("Service", service);
		
		JSONObject packageObject = new JSONObject();
		packageObject.put("Description", "AnHeGoods"); // 此处信息必填
		
		JSONObject packaging = new JSONObject();
		packaging.put("Code", "02");
		packaging.put("Description", "Nails");
		packageObject.put("Packaging", packaging);
		
		JSONObject dimensions = new JSONObject();
		dimensions.put("Length", "10");
		dimensions.put("Width", "30");
		dimensions.put("Height", "45");
		
		JSONObject dimensionsUnitOfMeasurement = new JSONObject();
		dimensionsUnitOfMeasurement.put("Code", "CM");
		dimensionsUnitOfMeasurement.put("Description", "cm");
		dimensions.put("UnitOfMeasurement", dimensionsUnitOfMeasurement);
		
		packageObject.put("Dimensions", dimensions);
		
		JSONObject packageWeight = new JSONObject();
		packageWeight.put("Weight", "5");
		
		JSONObject weightUnitOfMeasurement = new JSONObject();
		weightUnitOfMeasurement.put("Code", "KGS");
		weightUnitOfMeasurement.put("Description", "KG");
		packageWeight.put("UnitOfMeasurement", weightUnitOfMeasurement);
		
		packageObject.put("PackageWeight", packageWeight);
		
		shipment.put("Package", packageObject);
		
		shipmentRequest.put("Shipment", shipment);
		
		JSONObject labelSpecification = new JSONObject();
		JSONObject labelImageFormat = new JSONObject();
		labelImageFormat.put("Code", "GIF");
		labelImageFormat.put("Description", "GIF");
		labelSpecification.put("LabelImageFormat", labelImageFormat);
		labelSpecification.put("HTTPUserAgent", "Mozilla/4.5");
		shipmentRequest.put("LabelSpecification", labelSpecification);
		
		payload.put("ShipmentRequest", shipmentRequest);
		LOG.info("请求创建运单接口url={},请求参数request={}", SHIPPMENT_URL, payload);
		String respBody = HttpRequest.post(SHIPPMENT_URL).addHeaders(header).body(payload.toJSONString()).timeout(200000).execute()
				.body();
		LOG.info("获取面单返回结果respBody={}", respBody);
		try {
			FileUtils.write(new File("D:/UPS_RESP.txt"), respBody, "UTF-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
		// respBody={"response":{"errors":[{"code":"9120068","message":"Either credit card or account number information is needed but not both."}]}}
		if (StringUtils.isNotBlank(respBody)) {
			JSONObject respObject = JSON.parseObject(respBody);
			JSONObject shipmentResponse = respObject.getJSONObject("ShipmentResponse");
			if(shipmentResponse != null) {
				JSONObject response = shipmentResponse.getJSONObject("Response");
				JSONObject responseStatus = response.getJSONObject("ResponseStatus");
				String code = responseStatus.getString("Code");
				String description =responseStatus.getString("Description");
				if("1".equals(code)) {
					JSONObject shipmentResults = shipmentResponse.getJSONObject("ShipmentResults");
					String shipmentIdentificationNumber = shipmentResults.getString("ShipmentIdentificationNumber");
					
					JSONObject packageResults = shipmentResults.getJSONObject("PackageResults");
					String trackingNumber = packageResults.getString("TrackingNumber");
					
					JSONObject shippingLabel = packageResults.getJSONObject("ShippingLabel");
					JSONObject imageFormat = shippingLabel.getJSONObject("ImageFormat");
					String formatType = imageFormat.getString("Code");
					String graphicImage = shippingLabel.getString("GraphicImage");
					LOG.info("获取标签成功，shipmentIdentificationNumber={}, trackingNumber={}", shipmentIdentificationNumber, trackingNumber);
					Base64.decodeToFile(graphicImage, new File("D:/" + trackingNumber + "." + formatType));
					
				} else {
					LOG.info("获取UPS标签失败，description={}", description);
				}
				
			} else {
				JSONObject response = respObject.getJSONObject("response");
				JSONArray errorArray = response.getJSONArray("errors");
				if (errorArray != null && errorArray.size() > 0) {
					JSONObject errorObject = errorArray.getJSONObject(0);
					String code = errorObject.getString("code");
					String message = errorObject.getString("message");
					LOG.info("创建运单失败，code={}, message={}", code, message);
				} else {
					
				}
			}
		}
		return respBody;
	}

}
